﻿namespace RazorEngine.Web
{
    using System;
    using System.CodeDom.Compiler;
    using System.Linq;
    using System.Web;
    using System.Web.Compilation;

    using Compilation;
    using Templating;

    /// <summary>
    /// Defines a build provider for compiling razor templates in ASP.NET
    /// </summary>
    public abstract class RazorBuildProviderBase : BuildProvider
    {
        #region Fields
        private TypeContext TypeContext;
        private readonly CompilerServiceBase CompilerService;
        #endregion

        #region Constructor
        /// <summary>
        /// Initialises a new instance of <see cref="RazorBuildProviderBase"/>
        /// </summary>
        /// <param name="innerCompilerService">The internal compiler service.</param>
        protected RazorBuildProviderBase(CompilerServiceBase innerCompilerService)
        {
            if (innerCompilerService == null)
                throw new ArgumentNullException("innerCompilerService");

            CompilerService = innerCompilerService;
        }
        #endregion

        #region Methods
        /// <summary>
        /// Generates source code for the virtual path of the build provider, and adds the source code to a specified assembly builder.
        /// </summary>
        /// <param name="assemblyBuilder">The assembly builder that references the source code generated by the build provider.</param>
        public override void GenerateCode(AssemblyBuilder assemblyBuilder)
        {
            string className = VirtualPath.Substring(VirtualPath.LastIndexOf('/') + 1);
            className = className.Substring(0, className.LastIndexOf('.'));

            TypeContext = (TypeContext)HttpContext.Current.Items[className];

            assemblyBuilder.AddCodeCompileUnit(
                this,
                CompilerService.GetCodeCompileUnit(TypeContext.ClassName,
                                                               TypeContext.TemplateContent,
                                                               TypeContext.Namespaces,
                                                               TypeContext.TemplateType,
                                                               TypeContext.ModelType));

            foreach (var assembly in CompilerServices.GetLoadedAssemblies().Where(a => !a.IsDynamic))
                assemblyBuilder.AddAssemblyReference(assembly);
        }

        /// <summary>
        /// Returns a type generated by the build provider from the virtual path.
        /// </summary>
        /// <param name="results">The compilation results for the build provider's virtual path.</param>
        /// <returns>
        /// The type that is generated by the build provider for the virtual path. The base class returns null.
        /// </returns>
        public override Type GetGeneratedType(CompilerResults results)
        {
            if (results.Errors != null && results.Errors.Count > 0)
                throw new TemplateCompilationException(results.Errors);

            Type type = results.CompiledAssembly.GetType("CompiledRazorTemplates.Dynamic." + TypeContext.ClassName);
            return type;
        }
        #endregion
    }
}
